﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp6
{
    public class Chunk
    {
        public long StartOffset { get; private set; }
        public bool IsReadOnly { get; private set; }
        private readonly string _fileName;
        private readonly long _fileSize;
        private readonly int _maxReaderCount;
        private readonly int _readBufferSize;
        private readonly int _writeBufferSize;
        private WriteWorkItem _writeStream;
        private readonly ConcurrentQueue<ReaderWorkItem> _readFileStreams = new ConcurrentQueue<ReaderWorkItem>();
        private readonly ChunkDBConfig _chunkManagerConfig;

        public Chunk(string fileName, ChunkDBConfig chunkManagerConfig)
        {
            _fileName = fileName;
            _fileSize = chunkManagerConfig.DefaultChunkSize;
            _chunkManagerConfig = chunkManagerConfig;
            StartOffset = long.Parse(Path.GetFileNameWithoutExtension(fileName));
            _maxReaderCount = chunkManagerConfig.MaxReaderCount;
            _readBufferSize = chunkManagerConfig.ReadBufferSize;
            _writeBufferSize = chunkManagerConfig.WriteBufferSize;

        }

        public void InitCompletedChunk(string fileName)
        {
            FileInfo fileInfo = new FileInfo(fileName);
            File.SetAttributes(fileName, FileAttributes.ReadOnly);
        }

        public void InitOngoingChunk(string fileName)
        {
            // 如果需要特殊初始化操作，这里添加
            Stream stream = CreateWriteStream(fileName);
            _writeStream = new WriteWorkItem(stream);
        }

        public static Chunk InitNew(string fileName, ChunkDBConfig chunkManagerConfig)
        {
            Chunk chunk = new Chunk(fileName, chunkManagerConfig);
            chunk.InitNew(fileName);
            return chunk;
        }

        private void InitNew(String fileName)
        {
            var fileInfo = new FileInfo(fileName);
            if (fileInfo.Exists)
            {
                File.SetAttributes(fileName, FileAttributes.Normal);
                File.Delete(fileName);
            }
            var tempFilename = string.Format("{0}.{1}.tmp", fileName, Guid.NewGuid());
            var tempFile = new FileStream(tempFilename, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.Read,
                4096, FileOptions.SequentialScan);
            tempFile.SetLength(_chunkManagerConfig.DefaultChunkSize);
            tempFile.Flush(true);
            tempFile.Close();
            File.Move(tempFilename, fileName);
            Stream stream = CreateWriteStream(fileName);
            _writeStream = new WriteWorkItem(stream);
        }
        private void CreateReaderStreams()
        {
            for (int i = 0; i < _maxReaderCount; i++)
            {
                Stream stream = new FileStream(_fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, _readBufferSize,
                    FileOptions.None);
                _readFileStreams.Enqueue(new ReaderWorkItem(stream, new BinaryReader(stream)));
            }
        }
        private Stream CreateWriteStream(string fileName)
        {
            return new FileStream(_fileName, FileMode.Open, FileAccess.ReadWrite, FileShare.Read, _readBufferSize,
                    FileOptions.None);
        }

        public MessageWriteResult Append(IMessageExt data)
        {
            MessageWriteResult result = new MessageWriteResult();

            long oldPosition = _writeStream.Stream.Position;
            result.OldPosition = oldPosition;
            if (_writeStream.Stream.Position + data.TotalSize > _writeStream.Stream.Length)
            {
                result.Success = false;
                result.NewPosition = _writeStream.Stream.Position;
                return result; // 表示chunk已满，无法写入
            }
            data.WriteTo(_writeStream.Writer);
            long newPosition = _writeStream.Stream.Position;
            result.Success = true;
            result.NewPosition = newPosition;

            return result;
        }

        //public byte[] ReadAt(long offset, int length)
        //{
        //    byte[] buffer = new byte[length];
        //    try
        //    {
        //        _readStream.Seek(offset - StartOffset, SeekOrigin.Begin);
        //        _readStream.Read(buffer, 0, length);
        //    }
        //    finally
        //    {
        //        _lock.ExitReadLock();
        //    }

        //    return buffer;
        //}

        //public MessageLog ReadNextMessage()
        //{
        //    MessageLog messageLog = null;
        //    _lock.EnterReadLock();
        //    try
        //    {
        //        if (_readStream.Position >= _readStream.Length)
        //        {
        //            return null; // 表示已读取到最后，无更多消息
        //        }

        //        int messageLength;
        //        _readStream.Seek(-sizeof(int), SeekOrigin.Current); // 从当前位置向前读取4字节长度
        //        messageLength = BitConverter.ToInt32(new byte[sizeof(int)], 0);
        //        _readStream.Seek(-sizeof(int), SeekOrigin.Current); // 回到原位置

        //        if (_readStream.Position + messageLength > _readStream.Length)
        //        {
        //            throw new InvalidOperationException("Invalid message length or corrupted data.");
        //        }

        //        byte[] messageBody = new byte[messageLength];
        //        _readStream.Read(messageBody, 0, messageLength);

        //        messageLog = new MessageLog(messageLength, messageBody);
        //    }
        //    finally
        //    {
        //        _lock.ExitReadLock();
        //    }

        //    return messageLog;
        //}

        //public void Close()
        //{
        //    _lock.Dispose();
        //    _readStream.Close();
        //    _readStream.Dispose();
        //    _writeStream.Close();
        //    _writeStream.Dispose();
        //}

        public void Flush()
        {
            _writeStream.Stream.Flush();
            _writeStream.Stream.Close();
        }
    }
}
